// 版权所有2009 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package sync

import (
	"sync/atomic"
)

// Once是一个只执行一个操作的对象。
// 
// 第一次使用后不得复制一次。
type Once struct {
	// done表示是否已执行该操作。
	// 它是结构中的第一个，因为它用于热路径。
	// 热路径内联在每个呼叫站点。
	// 在某些体系结构（amd64/386）上，将“完成”放在第一位可以实现更紧凑的指令，
	// 在其他体系结构上，可以实现更少的指令（用于计算偏移量）。
	done uint32
	m    Mutex
}

// Do调用函数f的当且仅当Do被调用为
// 此实例第一次调用一次。换句话说，给定
// var一次
// if一次。Do（f）被多次调用，只有第一次调用才会调用f，
// 即使每次调用中f的值不同。
// 的一个新实例需要一次才能执行每个函数。
// 
// Do用于必须只运行一次的初始化。由于f 
// 是niladic，因此可能需要使用函数文字来捕获Do:
// 参数。一旦Do（func（）{config.init（filename）}）
// config调用的函数的
// 
// 因为在对f的一个调用返回之前，没有对Do的调用返回，如果f导致调用
// Do，它将死锁。
// 
// 如果f恐慌，您认为它已经回来了；Do的未来调用返回
// 而不调用f.
// 
func (o *Once) Do(f func()) {
	// 注意：这里是Do的一个错误实现：
	// 
	// if-atomic。与之相比，&o.done，0，1）{
	// f（）
	// }
	// 
	// Do保证当它返回时，f已经完成。
	// 此实现不会实现该保证：
	// 如果同时进行两次呼叫，cas的获胜者将
	// 呼叫f，第二个将立即返回，而不会等待第一个对f的呼叫完成。
	// 这就是为什么慢路径返回到互斥，以及为什么
	// 原子。StoreUint32必须延迟到f返回后。

	if atomic.LoadUint32(&o.done) == 0 {
		// 概述了慢路径，以允许快速路径的内联。
		o.doSlow(f)
	}
}

func (o *Once) doSlow(f func()) {
	o.m.Lock()
	defer o.m.Unlock()
	if o.done == 0 {
		defer atomic.StoreUint32(&o.done, 1)
		f()
	}
}
